#pragma once

#define WORKER_THREAD_IMPL_LOCKFREE

namespace Melting
{
	namespace Parallel
	{
		// NB : Work & WorkerThread are not related to TaskManager and its associated Task scheduling system

		//--------------------------------------------------------------------------------------------------------------------
		struct Work
		{
			virtual void Execute( void ) = 0;

			virtual void OnExecuted( void ) {};
		};

		//--------------------------------------------------------------------------------------------------------------------
		class WorkerThread : public Thread
		{
		public:
			WorkerThread( UINT32 _iCapacity );
			virtual ~WorkerThread( void );

			enum RunningMode
			{	RUN_ONCE	= 0
			,	RUN_FOREVER
			};

			/// Run the worker on all its tasks, and specify with _eMode = RUN_ONCE wether it should stop running when all tasks have been processed, or wait to process future tasks
			virtual bool        Run			( RunningMode _eMode = RUN_ONCE );
	 
			/// Adds a Work to process
			void                AddWork		( Work* _pWork );

			/// Returns the current nb of tasks to process
			INT32				GetNbWorks	( void ) const;

			/// Return the mode in which runs the WorkerThread
			RunningMode			GetRunningMode( void ) const;


		protected:
			/// Returns the current nb of tasks to process
			INT32				GetNbWorksReady( void ) const;

			void                ProcessNextWork( void );

			void                ProcessAllWorks( void );


			static ThreadFunctionReturn     Execute( void* _pWorker );

			AtomicCounter					miRunningMode;	///< Run Once only on the current Work queue if (mibOneShot == 1) , or loop forever waiting for more Works to come if (mibOneShot == 0)
			AtomicCounter					miNbWorks;		///< Number of Work remaining (i.e. that are waiting to be processed, or that are being processed)

		#ifdef WORKER_THREAD_IMPL_LOCKFREE
			LockFreeQueue< Work*, nullptr >			mWorkQueue;		///< Queue of Works to be processed
		#else
			AtomicCounter					miNbWorksReady;	///< Number of Work remaining AND ready to be processed
			mutable Mutex					mMutex;			///< Mutex to protect the Works queue
			std::list< Work* >				mlpWorks;		///< Queue of Works to be processed
		#endif
			
			AtomicCounter					mAbortRequested;///< Atomic used to request an abortion
		};

	} // namespace Parallel 
}// namespace Melting